package com.pl.redission;

import com.pl.redis.service.AbstractCacheService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

import static com.pl.redis.RedisKeys.KEY_SEPARATOR;

/**
 * Date            Author           Version
 * 2022/1/27 15:21  pengli         1.0
 */
@Slf4j
@Service
public class RedissonLockUtil extends AbstractCacheService {

    public final static String LOCK_PREFIX = "redisson_lock" + KEY_SEPARATOR;

    @Autowired
    private RedissonClient redissonClient;


    private String getKey(String lockKey) {
        return redisKeys.getProject() + KEY_SEPARATOR + redisKeys.getEnvironment() + KEY_SEPARATOR + LOCK_PREFIX + lockKey;
    }

    /**
     * 尝试获取锁, 并占用60秒,直到被释放<br/>
     * 调用tryLock后 一定要记得调用unlock()方法
     * @param lockKey   被锁的KEY
     * @return  如果获取失败, 则直接返回false;获取成功返回true
     */
    public boolean tryLock(String lockKey) {
        return tryLock(lockKey, 60);
    }

    /**
     * 尝试获取锁, 并占用指定时间<br/>
     * 调用tryLock后 一定要记得调用unlock()方法
     * @param lockKey   被锁的KEY
     * @param leaseTimeInSec    占用锁的时间
     * @return  如果获取失败, 则直接返回false;获取成功返回true
     */
    public boolean tryLock(String lockKey, long leaseTimeInSec) {
        String key = getKey(lockKey);
        log.info("try lock key: {}", key);
        RLock lock = redissonClient.getLock(key);

        try {
            return lock.tryLock(1L, leaseTimeInSec, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            log.warn("try to lock key: {}", key);
            log.warn("try lock error, e", e);
            return false;
        }
    }

    /**
     * 在指定时间内尝试获取锁, 并占用指定时间<br/>
     * 调用tryLock后 一定要记得调用unlock()方法
     * @param lockKey   被锁的KEY
     * @param waitTimeInMs     等待获取锁的时间, 单位: 毫秒
     * @param leaseTimeInMs    占用锁的时间, 单位: 毫秒
     * @return  如果获取失败, 则直接返回false;获取成功返回true
     */
    public boolean tryLock(String lockKey, long waitTimeInMs, long leaseTimeInMs) {
        String key = getKey(lockKey);
        log.info("try lock key: {}", key);
        RLock lock = redissonClient.getLock(key);

        try {
            return lock.tryLock(waitTimeInMs, leaseTimeInMs, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            log.warn("try to lock key: {}", key);
            log.warn("try lock error, e", e);
            return false;
        }
    }

    /**
     * 获取锁, 并占用给定的时间<br/>
     * 如果锁已被其他人占用, 则一直等待锁被其他人释放<br/>
     * 调用lock后 一定要记得调用unlock()方法
     * @param lockKey   被锁的KEY
     * @param leaseTimeInSec    占用锁的时间
     * @return
     */
    public void lock(String lockKey, long leaseTimeInSec) {
        String key = getKey(lockKey);
        log.info("lock key: {}", key);
        RLock lock = redissonClient.getLock(key);

        lock.lock(leaseTimeInSec, TimeUnit.SECONDS);
    }

    /**
     * 释放指定KEY的 锁
     * @param lockKey
     */
    public void unlock(String lockKey) {
        String key = getKey(lockKey);
        log.info("unlock key: {}", key);
        RLock lock = redissonClient.getLock(key);

        if (lock != null) {
            if (lock.isLocked()) {
                lock.unlock();
            }
        }
    }

}
